﻿using System;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;

namespace Assist
{
	public class ArcAssistFunc
	{
		public static XYZ GetArcMidPoint(Arc arc)
		{
			XYZ hyendPoint = arc.GetEndPoint(0);
            //hyendPoint - arc.Center;
			double num = arc.GetYJKEndParameter(1) - arc.GetYJKEndParameter(0);
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(arc.Normal, num / 2.0, arc.Center);
			return transform.OfPoint(hyendPoint);
		}

		public static XYZ GetPointAtParam(Arc arc, double param)
		{
			XYZ hyendPoint = arc.GetEndPoint(0);
            //hyendPoint - arc.Center;
			double num = arc.GetYJKEndParameter(1) - arc.GetYJKEndParameter(0);
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(arc.Normal, num * param, arc.Center);
			return transform.OfPoint(hyendPoint);
		}

		public static double GetParamAtPoint(Arc arc, XYZ ptOnArc)
		{
			double result;
			if (ptOnArc.IsAlmostEqualTo(arc.GetEndPoint(0)))
			{
				result = arc.GetYJKEndParameter(0);
			}
			else if (ptOnArc.IsAlmostEqualTo(arc.GetEndPoint(1)))
			{
				result = arc.GetYJKEndParameter(1);
			}
			else
			{
				double num = arc.GetYJKEndParameter(1) - arc.GetYJKEndParameter(0);
				XYZ xyz = ptOnArc - arc.Center;
				XYZ xyz2 = arc.GetEndPoint(0) - arc.Center;
				double num2;
				if (ArcAssistFunc.IsClockwise(arc))
				{
					num2 = xyz2.AngleOnPlaneTo(xyz, -XYZ.BasisZ);
				}
				else
				{
					num2 = xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
				}
				if (Math.Abs(num2 - Math.PI*2) < ArcAssistFunc.precision)
				{
					num2 = 0.0;
				}
				result = num2 / num;
			}
			return result;
		}

		public static double GetParamAtPoint1(Arc arc, XYZ ptOnArc)
		{
			double result;
			if (ptOnArc.IsAlmostEqualTo(arc.GetEndPoint(0)))
			{
				result = arc.GetYJKEndParameter(0);
			}
			else if (ptOnArc.IsAlmostEqualTo(arc.GetEndPoint(1)))
			{
				result = arc.GetYJKEndParameter(1);
			}
			else
			{
				XYZ xyz = ptOnArc - arc.Center;
				XYZ xyz2 = arc.GetEndPoint(0) - arc.Center;
				XYZ xyz3 = arc.GetEndPoint(1) - arc.Center;
				double num;
				double num2;
				if (ArcAssistFunc.IsClockwise(arc))
				{
					num = xyz2.AngleOnPlaneTo(xyz, -XYZ.BasisZ);
					num2 = xyz2.AngleOnPlaneTo(xyz3, -XYZ.BasisZ);
				}
				else
				{
					num = xyz.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
					num2 = xyz3.AngleOnPlaneTo(xyz2, XYZ.BasisZ);
				}
				if (Math.Abs(num - Math.PI*2) < ArcAssistFunc.precision)
				{
					num = 0.0;
				}
				result = arc.GetYJKEndParameter(0) + num / num2 * (arc.GetYJKEndParameter(1) - arc.GetYJKEndParameter(0));
			}
			return result;
		}

		public static bool IsClockwise(Arc arc)
		{
			XYZ normal = arc.Normal;
			XYZ xyz = normal.Normalize() - XYZ.BasisZ;
			return !xyz.IsZeroLength();
		}

		public static XYZ GetArcNormalVector(Arc arc, XYZ ptOnArc)
		{
			return (ptOnArc - arc.Center).Normalize();
		}

		public static XYZ GetArcTangentVector(Arc arc, XYZ ptOnArc)
		{
			XYZ xyz = (ptOnArc - arc.Center).Normalize();
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(XYZ.BasisZ, -Math.PI*.5, ptOnArc);
			return transform.OfVector(xyz);
		}

		public static OverlapType GetOverlapType(UIApplication uiApp, Arc a1, Arc a2)
		{
			XYZ zero = XYZ.Zero;
			XYZ zero2 = XYZ.Zero;
			return ArcAssistFunc.IsOverlapOfTwoArc(a1.GetEndPoint(0), a1.GetEndPoint(1), a1.Center, a2.GetEndPoint(0), a2.GetEndPoint(1), a2.Center, ref zero, ref zero2);
		}

		public static double GetStartAngle(Arc arc)
		{
			return ArcAssistFunc.getAngle(arc.Center, arc.GetEndPoint(0));
		}

		public static double GetEndAngle(Arc arc)
		{
			return ArcAssistFunc.getAngle(arc.Center, arc.GetEndPoint(1));
		}

		public static Plane GetPlane(Arc arc)
		{
			return RevitVersionFuncs.CreatePlanByNormalAndOrigin(arc.Normal, arc.Center);
		}

		public static OverlapType IsOverlapOfTwoArc(XYZ ptS1, XYZ ptE1, XYZ ptCenter1, XYZ ptS2, XYZ ptE2, XYZ ptCenter2, ref XYZ ptS, ref XYZ ptE)
		{
			if (!ptCenter1.IsAlmostEqualTo(ptCenter2))
			{
				return OverlapType.eNotOverlap;
			}
			double val = ptS1.DistanceTo(ptCenter1);
			double val2 = ptS2.DistanceTo(ptCenter2);
			if (!ArcAssistFunc.IsEqual(val, val2))
			{
				return OverlapType.eNotOverlap;
			}
			double angle = ArcAssistFunc.getAngle(ptCenter1, ptS1);
			double angle2 = ArcAssistFunc.getAngle(ptCenter1, ptE1);
			double angle3 = ArcAssistFunc.getAngle(ptCenter2, ptS2);
			double angle4 = ArcAssistFunc.getAngle(ptCenter2, ptE2);
			if ((ArcAssistFunc.IsEqual(angle, angle3) || ArcAssistFunc.IsEqual(Math.Abs(angle - angle3), Math.PI*2)) && (ArcAssistFunc.IsEqual(Math.Abs(angle2 - angle4), Math.PI*2) || ArcAssistFunc.IsEqual(angle2, angle4)))
			{
				ptS = ptS1;
				ptE = ptE1;
				return OverlapType.eOverlap;
			}
			if ((ArcAssistFunc.IsEqual(angle, angle4) || ArcAssistFunc.IsEqual(Math.Abs(angle - angle4), Math.PI*2)) && (ArcAssistFunc.IsEqual(Math.Abs(angle2 - angle3), Math.PI*2) || ArcAssistFunc.IsEqual(angle2, angle3)))
			{
				ptS = ptS1;
				ptE = ptE1;
				return OverlapType.eOverlap;
			}
			if (ArcAssistFunc.IsCoverAngle(angle, angle2, angle3) && ArcAssistFunc.IsCoverAngle(angle, angle2, angle4))
			{
				ptS = ptS2;
				ptE = ptE2;
				return OverlapType.e2Cover1;
			}
			if (ArcAssistFunc.IsCoverAngle(angle3, angle4, angle) && ArcAssistFunc.IsCoverAngle(angle3, angle4, angle2))
			{
				ptS = ptS1;
				ptE = ptE1;
				return OverlapType.e1Cover2;
			}
			if (ArcAssistFunc.IsCoverAngle(angle3, angle4, angle))
			{
				ptS = ptS1;
				ptE = ptE2;
				return OverlapType.ePartOverlap;
			}
			if (ArcAssistFunc.IsCoverAngle(angle, angle2, angle3))
			{
				ptS = ptS2;
				ptE = ptE1;
				return OverlapType.ePartOverlap;
			}
			return OverlapType.eNotOverlap;
		}

		private static bool IsCoverAngle(double sAngle, double eAngle, double testAngle)
		{
			double val = ArcAssistFunc.BetweenTheAngles(sAngle, eAngle, true);
			double num = ArcAssistFunc.BetweenTheAngles(sAngle, testAngle, true);
			double num2 = ArcAssistFunc.BetweenTheAngles(testAngle, eAngle, true);
			return ArcAssistFunc.IsEqual(val, num + num2);
		}

		public static double BetweenTheAngles(double dSAngle, double dEAngle, bool range2PI)
		{
			dSAngle = ArcAssistFunc.formatAngle(dSAngle);
			dEAngle = ArcAssistFunc.formatAngle(dEAngle);
			if (Math.Abs(dEAngle - dSAngle) < 1E-05)
			{
				return 0.0;
			}
			if (range2PI && dEAngle < dSAngle)
			{
				dEAngle += Math.PI*2;
			}
			return dEAngle - dSAngle;
		}

		public static double formatAngle(double angle)
		{
			int num = (int)(angle / Math.PI*2);
			double num2 = angle - (double)num * Math.PI*2;
			if (num2 < 0.0)
			{
				num2 += Math.PI*2;
			}
			return num2;
		}

		public static double getAngle(XYZ ptCenter, XYZ ptOut)
		{
			XYZ xyz = ptOut - ptCenter;
			double angle = XYZ.BasisX.AngleOnPlaneTo(xyz, XYZ.BasisZ);
			return ArcAssistFunc.formatAngle(angle);
		}

		public static bool IsEqual(double val1, double val2)
		{
			return !ArcAssistFunc.LessThan(val1, val2) && !ArcAssistFunc.LessThan(val2, val1);
		}

		public static bool LessThan(double val1, double val2)
		{
			return val1 - val2 < -1E-09;
		}

		protected static double precision = 1E-06;
	}
}
